﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Interop;
using Gw2Api;
using System.ComponentModel;
using Gw2WvWMapControl;
using System.Diagnostics;
using System.Speech.Synthesis;

namespace Gw2Overlay
{
    /// <summary>
    /// Interaction logic for GraphWindow.xaml
    /// </summary>
    public partial class GraphWindow : OverlayWindow
    {
        public WvWApi WvWApiInstance;
        private OverlordWindow _ow;
        public AudioNotification audio;
        public NamingConvention naming;
        public SpokenWorldNames spokenNames;
        public SpeakMapNames speakMapNames;
        public string voice;
        public string server;

        public GraphWindow(OverlordWindow ow)
        {
            InitializeComponent();
            this._ow = ow;
            this.audio = AudioNotification.None;
            MouseLeftButtonDown += delegate { _ow.SetShowStatusTooltip(false); };
            MouseLeftButtonUp += delegate { _ow.SetShowStatusTooltip(true); _ow.UpdateInfo(this); };
            WvWApiInstance = Gw2ApiFactory.WvWApi;
            wvWMapControl1.WvWApi = WvWApiInstance;
            wvWMapControl1.SliceUpdate += new WvWMapControl.SliceUpdateHandler(OnSliceUpdate);
            CreateContextMenu();
            Debug.WriteLine("WvWControl Width: " + wvWMapControl1.ActualWidth + ", Height:" + wvWMapControl1.ActualHeight);
        }

        protected override void OnInteractable(bool interactable)
        {
            if (interactable)
            {
                backrect.Visibility = System.Windows.Visibility.Visible;
                this.ResizeMode = ResizeMode.CanResizeWithGrip;
            }
            else
            {
                backrect.Visibility = System.Windows.Visibility.Hidden;
                this.ResizeMode = ResizeMode.NoResize;
            }
        }

        public void CreateContextMenu()
        {
            MenuItem matchups = this.Resources["Matchups"] as MenuItem;
            MenuItem matchupbyworld = this.Resources["MatchupByWorld"] as MenuItem;
            MenuItem systemvoice = this.Resources["SystemVoice"] as MenuItem;
            
            WorldNameApi names = Gw2ApiFactory.WorldNameApi;
            foreach (var match in WvWApiInstance.GetMatchups())
            {
                MenuItem mi = new MenuItem();
                mi.Header = match.GetRegionShort() + " T" + match.GetTier() + " | " + match.ToString(names);
                mi.Click += new RoutedEventHandler(MatchClick);
                mi.Tag = match.wvw_match_id;
                matchups.Items.Add(mi);
            }

            matchups.Items.SortDescriptions.Add(new SortDescription("Header", ListSortDirection.Ascending));

            foreach (var name in names.GetWorldNames())
            {
                MenuItem mi = new MenuItem();
                mi.Header = name;
                mi.Click += new RoutedEventHandler(WorldClick);
                var wid = names.GetWorldIdFromName(name);
                mi.Tag = wid;
                matchupbyworld.Items.Add(mi);
            }

            foreach (var voice in TtsService.Instance.GetInstalledVoices())
            {
                VoiceInfo info = voice.VoiceInfo;
                MenuItem mi = new MenuItem();
                mi.Header = info.Name;
                mi.Click += new RoutedEventHandler(SystemVoiceClick);
                mi.Tag = info.Name;
                systemvoice.Items.Add(mi);
            }
        }

        private void OnSliceUpdate(object sender, WvWMapControl.SliceUpdateEventArgs e)
        {
            var diff = e.diff;
            switch (audio)
            {
            case AudioNotification.Voice:
                {
                    var objective = wvWMapControl1.WvWApi.GetObjectivePropertyById(diff.objectiveId);
                    if (null != objective && objective.type != Objective.ObjectiveType.Ruins)
                    {
                        string s = Util.GetSpokenWorldName(WvWApiInstance, diff.matchupId, diff.to, this.spokenNames) + " has taken " + Util.GetSpokenObjectiveName(objective, naming);
                        if ((this.speakMapNames == SpeakMapNames.Auto && _ow.WindowCount > 1) || this.speakMapNames == SpeakMapNames.On)
                        {
                            s += " in " + Util.GetSpokenMapName(WvWApiInstance, diff.matchupId, objective, this.spokenNames);
                        }
                        TtsService.Instance.Speak(s);
                    }
                }
                break;
            }
        }

        private void NewWindowClick(object sender, RoutedEventArgs e)
        {
            _ow.CreateNewGraphWindow(this.wvWMapControl1.WvWMap, this.wvWMapControl1.WvWMatchup, 0, 0);
        }

        private void CloseClick(object sender, RoutedEventArgs e)
        {
            _ow.CloseWindow(this);
            this.Close();
        }

        private void QuitClick(object sender, RoutedEventArgs e)
        {
            Debug.Flush();
            _ow.Shutdown();
        }

        private void SoundClick(object sender, RoutedEventArgs e)
        {
            MenuItem mi = (MenuItem)sender;
            string sound = mi.Tag.ToString();
            AudioNotification au = AudioNotification.None;
            if (Enum.TryParse<AudioNotification>(sound, false, out au))
            {
                this.audio = au;
            }
            _ow.UpdateInfo(this);
        }

        private void NamingClick(object sender, RoutedEventArgs e)
        {
            MenuItem mi = (MenuItem)sender;
            string tag = mi.Tag.ToString();
            NamingConvention convention = NamingConvention.Names;
            if (Enum.TryParse<NamingConvention>(tag, false, out convention))
            {
                this.naming = convention;
            }
            _ow.UpdateInfo(this);
        }

        private void SpokenNamesClick(object sender, RoutedEventArgs e)
        {
            MenuItem mi = (MenuItem)sender;
            string tag = mi.Tag.ToString();
            SpokenWorldNames names = SpokenWorldNames.Names;
            if (Enum.TryParse<SpokenWorldNames>(tag, false, out names))
            {
                this.spokenNames = names;
            }
            _ow.UpdateInfo(this);
        }

        private void SpeakMapNamesClick(object sender, RoutedEventArgs e)
        {
            MenuItem mi = (MenuItem)sender;
            string tag = mi.Tag.ToString();
            SpeakMapNames speakNames = SpeakMapNames.Auto;
            if (Enum.TryParse<SpeakMapNames>(tag, false, out speakNames))
            {
                this.speakMapNames = speakNames;
            }
            _ow.UpdateInfo(this);
        }

        private void SystemVoiceClick(object sender, RoutedEventArgs e)
        {
            MenuItem mi = (MenuItem)sender;
            string tag = mi.Tag.ToString();
            this.voice = tag;
            TtsService.Instance.SelectVoice(tag);
            _ow.UpdateInfo(this);
        }

        private void MapClick(object sender, RoutedEventArgs e)
        {
            MenuItem mi = (MenuItem)sender;
            string map = mi.Name;
            try
            {
                this.wvWMapControl1.PositionApi = null;
                this.wvWMapControl1.WvWMap = (WvWMaps)Enum.Parse(typeof(WvWMaps), map, true);
            }
            catch (Exception)
            {
                this.wvWMapControl1.PositionApi = Gw2ApiFactory.PositionApi;
            }
            _ow.UpdateInfo(this);
        }

        private void MatchClick(object sender, RoutedEventArgs e)
        {
            MenuItem mi = (MenuItem)sender;
            string id = mi.Tag.ToString();
            this.wvWMapControl1.WvWMatchup = id;
            this.server = null;
            _ow.UpdateInfo(this);
        }

        private void WorldClick(object sender, RoutedEventArgs e)
        {
            WorldNameApi names = Gw2ApiFactory.WorldNameApi;
            MenuItem mi = (MenuItem)sender;
            string id = mi.Tag.ToString();
            this.server = id;
            this.wvWMapControl1.WvWMatchup = WvWApiInstance.GetMatchupByWorldNameV2(names.GetWorldFromId(id)).id;
            _ow.UpdateInfo(this);
        }

        private void ResizeClick(object sender, RoutedEventArgs e)
        {
            MenuItem mi = (MenuItem)sender;
            GraphWindowSizes size = (GraphWindowSizes)Enum.Parse(typeof(GraphWindowSizes), mi.Tag.ToString(), true);
            this.Width = (int)size;
            this.Height = (int)size;
            _ow.UpdateInfo(this);
        }

        private void TransparentClick(object sender, RoutedEventArgs e)
        {
            MenuItem mi = (MenuItem)sender;
            int value = Convert.ToInt32(mi.Tag.ToString());
            double opactiy = value / 100.0;
            this.Opacity = opactiy;
            _ow.UpdateInfo(this);
        }

        override public void DoHitTest(Point pt)
        {
            try
            {
                Visual target = this.wvWMapControl1.HitTestTarget;
                HitTestResult result = VisualTreeHelper.HitTest(target, target.PointFromScreen(pt));
                if (null != result && result.VisualHit is Shape)
                {
                    this.wvWMapControl1.SetHighlightElement((Shape)result.VisualHit);
                }
                else
                {
                    this.wvWMapControl1.ClearHighlightElement();
                }
            }
            catch (Exception)
            {
            }
        }

        private void WindowSizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.Height = e.NewSize.Width;
            _ow.UpdateInfo(this);
        }
    }


    public enum GraphWindowSizes
    {
        Tiny = 70,
        Small = 120,
        Medium = 170,
        Large = 220,
        Huge = 320,
    }

    public enum AudioNotification
    {
        None,
        Voice,
        Ping,
        Beep,
    }

    public enum NamingConvention
    {
        Names,
        Cardinal,
        CardinalExceptKeeps,
    }

    public enum SpokenWorldNames
    {
        Colors,
        Names,
    }

    public enum SpeakMapNames
    {
        Auto,
        On,
        Off,
    }
}
